package com.haixiaoke.saas.filter;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.haixiaoke.saas.common.utils.RequestAesUtils;
import com.haixiaoke.saas.common.wrapper.RequestWrapper;
import com.haixiaoke.saas.common.wrapper.ResponseWrapper;
import com.haixiaoke.saas.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * @Author panda
 * @Date 2023/8/5
 **/
@Slf4j
@Component
public class DecryRequestFilter implements Filter {

    /**
     * 排除加密解密的接口
     */
    @Value("${aesEncrypt.excludeUrls:}")
    private String[] excludeUrls;

    private List<String> excludes;

    @Autowired
    private ISysConfigService iSysConfigService;


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        excludes = Arrays.asList(excludeUrls);
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        boolean requestEnabled = iSysConfigService.selectRequestEnabled();
        //关闭接口加密解密开关
        if (!requestEnabled) {
            // 这里是过滤器注册转发
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        HttpServletRequest req = (HttpServletRequest) servletRequest;

        // 允许跳过的接口
        if (handleExcludeUrl(req)) {
            // 这里是过滤器注册转发
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
        //获取请求体里的参数报文
        String body = new String(requestWrapper.getBody());
        //获取请求路径后的请求参数报文
        String parameter = requestWrapper.getParameter("encode");
        if (StrUtil.isNotEmpty(body)) {
            JSONObject jsonObject = JSONObject.parseObject(body);
            String encode = jsonObject.getString("encode");
            String decrypt = RequestAesUtils.decrypt(encode);
            if (StrUtil.isNotEmpty(decrypt)) {
                requestWrapper.setBody(decrypt.getBytes(StandardCharsets.UTF_8));
            } else {
                log.error("请求体请求参数解密异常,URL:{}",req.getServletPath());
            }

        } else if (StrUtil.isNotEmpty(parameter)) {

            String decrypt = RequestAesUtils.decrypt(parameter);
            if (StrUtil.isNotEmpty(decrypt)) {
                log.error("路径参数请求参数解密异常");
                //拆分json格式数据，转为map
//            Map<String,Object> map = JSONObject.parseObject(decrypt, Map.class);
                //拆分get请求路径带参的数据，转为map
                String[] strs = decrypt.split("&");
                Map<String, Object> map = new HashMap<>();
                for (int i = 0; i < strs.length; i++) {
                    String[] str = strs[i].split("=");
                    map.put(str[0], str.length >1 ? str[1] : null);
                }
                requestWrapper.addAllParameters(map);
            } else {
                log.info("get解密的param：{}", req.getServletPath());
            }

        }

        this.encryptResultData(filterChain, servletResponse, requestWrapper);

    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }

    private boolean handleExcludeUrl(HttpServletRequest request) {
        if (CollectionUtils.isEmpty(excludes)) {
            return false;
        }
        String url = request.getServletPath();
        for (String pattern : excludes) {
            Pattern p = Pattern.compile("^" + pattern);
            Matcher m = p.matcher(url);
            if (m.find()) {
                return true;
            }
        }
        return false;
    }

    /**
     * @description: 加密返回数据
     * @param: [chain,
     * response, requestWrapper]
     * @return: void
     * @date: 2022/4/12 18:16
     */
    public void encryptResultData(FilterChain chain, ServletResponse response, RequestWrapper requestWrapper) {
        // 且对返回数据进行加密 ,此地方代码过于冗余后续可能需要对整个方法进行优化
        try {
            // 请注意响应处理 包装响应对象 res 并缓存响应数据,只有需要加密数据才使用这个 ResponseWrapper
            ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response);
            // 执行业务逻辑 交给下一个过滤器或servlet处理
            // 这里是过滤器注册转发
            chain.doFilter(requestWrapper, responseWrapper);
            // 是否结果加密
            byte[] resData = responseWrapper.getResponseData();
            // 设置响应内容格式，防止解析响应内容时出错
            // responseWrapper.setContentType("text/plain;charset=UTF-8");
            // 加密响应报文并响应
            String resultEncrypt = RequestAesUtils.encrypt(new String(resData));
            // 这里得用原始的流去处理返回 切记
            PrintWriter out = response.getWriter();
            out.print(resultEncrypt);
            out.flush();
            out.close();

        } catch (Exception e) {
            log.error("返回数据加密失败：{}", e.getMessage());
            try {
                getFailResponse((HttpServletResponse) response);
            } catch (IOException ioException) {
                log.error("io异常：{}", ioException.getMessage());
            }

        }
    }

    private void getFailResponse(HttpServletResponse response) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        out = response.getWriter();
        // 加密后的错误消息
        out.write("服务端加密异常");
        out.flush();
        out.close();
    }
}
